Git Kata 3: Merging

Learn about merging branches with divergent histories.

Merging is essentially the opposite of branching. Branches allow changes in a repository to be separated. Merging is the process of combining work that’s separated between branches.

Step 1: Merge changes between branches#

The command to merge changes is given below.

The output will be something like this:

Merging changes

Command's Parameters

Command / Parameter

Description

merge

This applies the changes from one branch to another branch.

newbranch

This is the branch from which we take commits and apply them to the current branch.

The git merge command replays the changes from another branch on the current branch. Git will attempt to combine the commits from the source branch to the current branch. The result of the merge operation depends on the differences (if there are any) between the branches. The output of this command is:

Output

Message

Meaning

"Updating c70b36e..1e19013"

This is the abbreviated source and the target commit hashes.

"Fast-forward"

This is the merge strategy used to merge the source and target branches.

"storelist.txt | 4++--"

These are the files affected by the merge and the lines that were modified.

"1 file changed, 2 insertions(+), 2 deletions(-)"

This is a summary of the files changed and the modifications made.

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f.. First line last
61dd33f.. First...
Viewer does not support full SVG 1.1
Take the changes from newbranch and apply them to the current branch

The previous step made a modification to storelist.txt in newbranch. The git merge newbranch command instructs Git to take the changes from newbranch and apply them to the current branch.

Git has several methods, called merge strategies, it can use to determine how to merge changes. This execution of Git merge uses the fast-forward strategy.

The main branch had no commits on it since the newbranch commit was added. Git was able to merge them efficiently by simply moving the HEAD and main refs to point to the latest commit in the commit history. When Git executes a fast-forward merge, only the refs are updated, so no new commits are necessary. Git merged the changes by updating the HEAD and main refs to point to the commit in newbranch. The next step will demonstrate merging where different versions of the same file exist in both branches.

Switch back to the text editor and reload the file.

Reloading a file in the text editor

The merge operation has updated storelist.txt in the working directory, applying the changes made in newbranch to the current branch, main. The “First line last” commit from newbranch has been applied to the main branch.

Step 2: Merge branches with divergent histories#

To append the text in the file and save:

  • Add (I love yogurt!) to the second line.
  • Save the changes.
Appending (I love yogurt!) to the second line in the file

The next several steps will demonstrate merging two branches with differing versions of the same file. This step makes the first change to storelist.txt while main is the current branch.

The command to commit the change to the repository is given below.

When we execute the command above, the output will be something like this:

Committing the changes to the repository

Command's Parameters

Command / Parameter

Description

commit

This creates a new commit in the current branch.

-a

This stages all the modified files prior to the commit.

-m

This sets a commit message on the command line.

"Loving yogurt"

This is the commit message.

This step commits the change just made to storelist.txt in the main branch.

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f..
First line last
61dd33f.....
70c144e..
Loving yogurt!
70c144e.....
Viewer does not support full SVG 1.1
A new commit has been added to the main branch; main is now one commit ahead of newbranch

The command to witch to newbranch is given below.

The result will be something like this:

Switching to newbranch

Command's Parameters

Command / Parameter

Description

checkout

This checks out a commit or switches to a branch.

newbranch

This is the branch to be checked out.

This step checks out newbranch.

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f..
First line last
61dd33f.....
70c144e..
Loving yogurt!
70c144e.....
Viewer does not support full SVG 1.1
Checking out newbranch moves the HEAD ref to the last commit in newbranch

To append the text in the file and save:

  • Return to the text editor and reload the file.
  • Add (lowfat please) to Moo Milk.
  • Enter “Ctrl”+“S” to save.
Appending (lowfat please) to Moo Milk

This step makes a change on newbranch to a different line than the one changed in the main branch.

The command to commit the change to the repository is given below.

After the execution of the above command, the output will be something like this:

Committing the changes to the repository

Command's Parameters

Command / Parameter

Description

commit

This creates a new commit in the current branch.

-a

This stages all the modified files prior to the commit.

-m

This sets a commit message on the command line.

"Lowfat milk"

This is the commit message.

This step commits the change made to the Moo Milk line.

The output of this command is:

Output

Message

Meaning

"newbranch [ec8be18] Lowfat milk]"

This is the branch to which the commit was applied, the abbreviated hash of the commit, and the commit message

"1 file changed, 1 insertion(+), 1 deletion(-)"

This is the number of files changed and lines inserted and deleted

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f..
First line last
61dd33f.....
70c144e..
Loving yogurt!
70c144e.....
90368b0..
Lowfat milk
90368b0.....
Viewer does not support full SVG 1.1
Truly divergent commit history

The updated visualization shows a truly divergent commit history. There are now two different versions of storelist.txt: one version in main and a different version in newbranch. The HEAD ref points to the commit in newbranch because it’s the most recent commit, and newbranch is the current branch.

The command to switch to main is given below.

The output of this command will be something like this:

Switching to the main branch

Command's Parameters

Command / Parameter

Description

checkout

This checks out a commit or switches to a branch.

master

This is the branch to be checked out.

This step uses git checkout to switch back to the main branch.

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f..
First line last
61dd33f.....
70c144e..
Loving yogurt!
70c144e.....
90368b0..
Lowfat milk
90368b0.....
Viewer does not support full SVG 1.1
Checking out main moves the HEAD ref to the last commit on main

The command to display the differences between main and newbranch is given below:

After the execution of the above command, the output will be something like this:

Displaying the difference between main and newbranch

Command's Parameters

Command / Parameter

Description

diff

This displays the difference between objects, including commits, branches, the working tree, and index.

newbranch

This execution of git diff indicates a branch, newbranch. This compares the current main branch with newbranch.

The git diff command is used to compare two objects. This step uses git diff to view the differences between the main branch and newbranch. git diff can be used to view the differences in branches when preparing for a merge.

The text-based format of the git diff command shows differences between the two compared objects. When comparing two branches, as this execution does, all the differences are listed. If there were more than one file with differences in the repository, they would be included in the output.

The output of git diff is designed to be machine-readable so that it can be fed into other commands and programs. Graphical diff tools present a more readable visual difference report. It’s possible and useful to learn to read this format.

The output of the command is:

Output

Message

Meaning

"diff --git a/storelist.txt b/storelist.txt"

This is the header, indicating that the output includes a “version a” and “version b” of storelist.txt.

"index 694789f..166a8e7 100644"

This line indicates the hashes of the two files. The first hash is the “a” version, the second hash is the “b” version. The 100644 code details the type and permissions of the file.

"--- a/storelist.txt"

This is the “from” version. It's the version that was modified first. The differences in this version are prepended in the output with the minus (-) sign and are colored red.

"+++ b/storelist.txt"

This is the “to” version. The differences in this version are prepended in the output with the plus (+) sign and are colored green.

"@@ -1,9 +1,9 @@"

This line indicates a difference hunk.

  • -1,9: This is a range of lines for the “from” version. The minus (-) sign indicates the version of the file, which is the “a” version (not a negative number.) This hunk starts at the first line and extends to the ninth line in the “from” version.
  • +1,9: This is a range of lines for the “to” version. The plus (+) sign indicates the version of the file, which is the “b” version (not a positive number.) This hunk starts at the first line and extends to the ninth line in the “to” version.

The remaining lines indicate the lines present in one version and not in the other.

"-Yummy Yogurt"

This line is in the “from” or “a” version, indicated by the minus (-) sign.

"+Yummy Yogurt (I love yogurt!)"

This line is in the “from” or “a” version, indicated by the minus (-) sign.

"-Moo Milk (lowfat please)"

This line is in the “from” or “a” version, indicated by the minus (-) sign.

"+Moo Milk"

This line is in the “to” or “b” version, indicated by the plus (+) sign.

This output displays the differences in storelist.txt between the main and newbranch branches. With practice, we can learn to use this information to predict the results of a merge. Graphical tools are also available to display the differences visually, which makes that process easier.

The commands to merge the commits on newbranch to main are given below.

  • Click “Ctrl”+“O.”
  • Click “Enter.”
  • Click “Ctrl”+“X.”
  • View storelist.txt in the editor.
  • Reload to see the changes.

The output will be something like this:

Merging the commits on newbranch to the main

Commands

Command / Parameter

Description

merge

This applies changes from one branch to another branch.

newbranch

This is the branch from which we take commits and apply them to the current branch.

Ctrl+O | Enter | Ctrl+X

This saves and exits the nano editor, saving the commit message of the merge commit.

This step creates a merge using the same command as in the previous step. However, the results of this merge are quite different due to the fact that it’s not a fast-forward merge.

The commit histories of main and newbranch are different in this case, so Git cannot perform a fast-forward merge. Git must perform a three-way merge. A three-way merge takes two commits and combines them together in a third commit: a merge commit. Merge commits are different from the commits we’ve seen so far in that they have two (or more) parents instead of one.

The default merge strategy, in this case, is called recursive. This execution of the Git merge resulted in an auto-merge. The Git merge algorithm has some smarts built into it so that Git can merge automatically whenever possible.

The recursive merge strategy favors the current branch by default (known as the ours option). Git assumes that we want the current branch, main, to take priority when merging. The differences in storelist.txt are on different lines, so Git can infer the result of the merge. The next kata will demonstrate a case where Git can’t guess what we want, so the conflicts must be resolved by hand.

The output of this command is:

Output

Message

Meaning

"Auto-merging storelist.txt"

This indicates that Git was able to merge the branches automatically.

"Merge made by the ‘recursive’ strategy"

This indicates the strategy used to perform the merge.

"storelist.txt | 2 +-"

This is a list of the files affected and the number of lines modified.

"1 file changed, 1 insertion(+), 1 deletion(-)"

This is a summary of the changes that were made in the merge.

Note: We can refer to the output from the previous git diff command to track the changes that are applied by the merge:

-Moo Milk (lowfat please): This line is in the “from” version. It will be present in the merge result because there’s no conflicting change in the main branch version. This is the 1 insertion(+) from the output.

+Moo Milk: This line is in the “to” version in the main branch. This line hasn’t changed in the main branch since the change in newbranch, so Git applies the other version. This is the “1 deletion(-)” from the output.

e137e9b...
first commit
e137e9b......
28df86f..
Reordered List
28df86f.....
823c7c8..
Another reorder
823c7c8.....
main
main
HEAD
HEAD
newbranch
newbranch
61dd33f..
First line last
61dd33f.....
70c144e..
Loving yogurt!
70c144e.....
90368b0..
Lowfat milk
90368b0.....
dbf84a9..
Merge
dbf84a9.....
Viewer does not support full SVG 1.1
The visualization now shows the result of our merge

Note: The latest commit is the merge commit created by the merge. Merge commits have at least two parents.

Practice commands#

We’ve given a terminal and a table containing a list of commands discussed in this lesson. Try out these commands after running the terminal and check out the results!

Commands

Step

Command

This merges the changes from newbranch to main.

git merge newbranch

  1. This reloads storelist.txt in the text editor.
  2. It also appends the text “(I love yogurt!)” to the “Yummy Yogurt” line in the text editor and saves the file.



nano storelist.txt

This commits the change to the repository, setting the commit comment from the command line.


git commit -a -m "Loving yogurt"

This switches to newbranch.

git checkout newbranch

This appends the text “(lowfat please)” to the “Moo Milk” line in the text editor and saves the file.


nano storelist.txt

This commits the change to the repository, setting the commit comment from the command line.


git commit -a -m "Lowfat milk"

This switches to main.

git checkout master

This displays the differences between main and newbranch.

git diff newbranch

This merges the commits on newbranch to main.

git merge newbranch


This views storelist.txt in the editor; reload to see changes.

nano storelist.txt

Ctrl+O

Enter

Ctrl+X 

Terminal 1
Terminal

Click to Connect...

Git Kata 2: Branches

Git Kata 4: Merge Conflicts